#include <stdio.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <fcntl.h>
#include "time.h"

#define uint32_t  unsigned int

struct SpiMsg {
    unsigned char *wbuf;       /**< Address of the write buffer */
    unsigned char *rbuf;       /**< Address of the read buffer */
    uint32_t len;        /**< Length of the read and write buffers. The read buffer and the write
                          * buffer have the same length.
                          */
    uint32_t speed;      /**< Current message transfer speed */
    unsigned short delayUs;    /**< Delay (in microseconds) before starting the next transfer.
                          * The value <b>0</b> indicates there is no delay between transfers.
                          */
    unsigned char keepCs;    /**< Whether to keep CS active after current transfer has been
                          * completed. <b>1</b> indicates to keeps CS; <b>0</b> indicates to switch off the CS.
                          */
};

struct SpiIocMsg {
    struct SpiMsg *msg;
    int count;
};

#define SPI_CPHA		0x01
#define SPI_CPOL		0x02

#define SPI_MODE_0		(0|0)
#define SPI_MODE_1		(0|SPI_CPHA)
#define SPI_MODE_2		(SPI_CPOL|0)
#define SPI_MODE_3		(SPI_CPOL|SPI_CPHA)

#define SPI_IOC_MAGIC 'k'
#define SPI_IOC_MESSAGE                 _IOW(SPI_IOC_MAGIC, 0, struct SpiIocMsg)
#define SPI_IOC_RD_MODE                 _IOR(SPI_IOC_MAGIC, 1, uint32_t)
#define SPI_IOC_RD_LSB_FIRST            _IOR(SPI_IOC_MAGIC, 2, uint32_t)
#define SPI_IOC_RD_BITS_PER_WORD        _IOR(SPI_IOC_MAGIC, 3, uint32_t)
#define SPI_IOC_RD_MAX_SPEED_HZ         _IOR(SPI_IOC_MAGIC, 4, uint32_t)
#define SPI_IOC_WR_MODE                 _IOW(SPI_IOC_MAGIC, 1, uint32_t)
#define SPI_IOC_WR_LSB_FIRST            _IOW(SPI_IOC_MAGIC, 2, uint32_t)
#define SPI_IOC_WR_BITS_PER_WORD        _IOW(SPI_IOC_MAGIC, 3, uint32_t)
#define SPI_IOC_WR_MAX_SPEED_HZ         _IOW(SPI_IOC_MAGIC, 4, uint32_t)

//spidev0.0
#define DEV_NAME "/dev/spidev2.0"

#define CMD_SETA_UPDATEA 0x18    // A通道命令+16位A路数据
#define CMD_SETB_UPDATEB 0x19    // B通道命令+16位B路数据
#define CMD_UPDATE_ALL_DACS 0x0F // 更新两路寄存器命令，后16位只需时钟即可

#define CMD_GAIN 0x02             // 内部放大倍数命令
#define DATA_GAIN_B2_A2 0x0000   // B路2倍，A路2倍
#define DATA_GAIN_B2_A1 0x0001   // B路2倍，A路1倍
#define DATA_GAIN_B1_A2 0x0002   // B路1倍，A路2倍
#define DATA_GAIN_B1_A1 0x0003   // B路1倍，A路1倍

#define CMD_PWR_UP_A_B 0x20    // 命令：上电A、B路
#define DATA_PWR_UP_A_B 0x0003 // 数据：Power up DAC-A and DAC-B	data

#define CMD_RESET_ALL_REG 0x28    // 命令：所有寄存器复位、清空寄存器
#define DATA_RESET_ALL_REG 0x0001 // 数据：所有寄存器复位、清空寄存器

#define CMD_LDAC_DIS 0x30       // LDAC脚功能命令
#define DATA_LDAC_DIS 0x0003    // LDAC脚不起作用

#define CMD_INTERNAL_REF_DIS 0x38    // 命令：Disable internal reference and reset DACs to gain = 1
#define DATA_INTERNAL_REF_DIS 0x0000 // 数据：Disable internal reference and reset DACs to gain = 1
#define CMD_INTERNAL_REF_EN 0x38     // 命令：Enable Internal Reference & reset DACs to gain = 2
#define DATA_INTERNAL_REF_EN 0x0001  // 数据：Enable Internal Reference & reset DACs to gain = 2

int fd = 0;

//DAC8562寄存器数据写入
void DAC_WR_REG(unsigned char cmd_byte, unsigned short data_byte)
{
    unsigned char buf[3] = {0};
    buf[0] = cmd_byte;
    buf[1] = data_byte >> 8;
    buf[2] = data_byte & 0xFF;
    // printf("write %x %x %x\n", buf[0], buf[1], buf[2]);
    write(fd, buf, 3);
}

int main(int argc, char **argv)
{
    printf("\n************************************************\n");
    
    int ret = 0;
    int i = 0;

    fd = open(DEV_NAME, O_RDWR);
    if(fd == 0){
        printf("open %s failed error: %d\n",DEV_NAME, fd);
        return -1;
    }else{
        printf("open %s sucess fd: %d\n",DEV_NAME, fd);
    }
    unsigned long arg = SPI_MODE_2;
    ioctl(fd, SPI_IOC_WR_MODE, &arg);
    arg = 50000000; 
    ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &arg);//设置传输频率

	DAC_WR_REG(CMD_RESET_ALL_REG, DATA_RESET_ALL_REG);
	DAC_WR_REG(CMD_PWR_UP_A_B, DATA_PWR_UP_A_B);
	DAC_WR_REG(CMD_INTERNAL_REF_EN, DATA_INTERNAL_REF_EN);
	DAC_WR_REG(CMD_GAIN, DATA_GAIN_B2_A2);
	DAC_WR_REG(CMD_LDAC_DIS, DATA_LDAC_DIS);

    printf("set A and B\n");
    getchar();
    //0x8000 - 0xC000
    DAC_WR_REG(CMD_SETA_UPDATEA, 0xC000);
    DAC_WR_REG(CMD_SETB_UPDATEB, 0xC000);
    printf("wait \n");
    getchar();


    close(fd);
    printf("\n************************************************\n\n");
    
    return 0;
}